//============================================================================
// Name        : CL.cpp
// Author      : uturan
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <stdio.h>
#include <sys/mman.h>
#include "URT.h"
#include "DART.h"
#include <signal.h>

using namespace std;

/* names for device files */
#define DEVICE_FILE "/dev/hello"

enum {
	CL_DART,
	CL_URT
};

void* debugLatency(void* arg)
{
	extern int quit;
	struct sched_param scheduling_parameters;
	scheduling_parameters.sched_priority = 80; 
	sched_setscheduler(0, SCHED_FIFO, &scheduling_parameters);
	U32 i;
	CLProtocol* CL = (CLProtocol*)arg;
	TimeInternal timeout = {1, 0};
	char tdiffstr[100];
	U32 LATENCY_ARRAY_COUNT = 2;

	int fd[LATENCY_ARRAY_COUNT];
	fd[0] = open("testmqueueLatency", O_TRUNC | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	fd[1] = open("kerneltest", O_TRUNC | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

	sprintf(tdiffstr, "current \t min \t max \t avg \t count\n");
	for(i=0; i<LATENCY_ARRAY_COUNT; i++) {
		if( fd[i] < 0) {
			DBG( strerror(errno) );
			exit(EXIT_FAILURE);
		}
		else {
			write(fd[i], tdiffstr, strlen(tdiffstr));
		}
	}


	for(;;){
		for(i = 0; i < LATENCY_ARRAY_COUNT; i++) {
			if( CL->updatedLatency[i] ) {
				sprintf(tdiffstr,"%9d,%9d,%9d,%9d, %d\n", CL->curLatency[i], CL->minLatency[i], CL->maxLatency[i], CL->avgLatency[i], CL->cntLatency[i]);
				write(fd[i], tdiffstr , strlen(tdiffstr));
				CL->updatedLatency[i] = false;
			}
		}
		nanoSleep(&timeout);

		if(quit) {
			break;
		}
	}
	for(i=0; i<LATENCY_ARRAY_COUNT; i++) {
		close(fd[i]);
	}

	pthread_exit(NULL);
	return NULL;
}

int main(int argc, char **argv) {

	if (mlockall(MCL_CURRENT | MCL_FUTURE)) {/*Lock all process memory pages in RAM(disable paging)*/
	   		perror("mlockall failed:");
	   		exit(EXIT_FAILURE);
	}

	struct sched_param scheduling_parameters;
	scheduling_parameters.sched_priority = sched_get_priority_max(SCHED_FIFO);
	sched_setscheduler(0, SCHED_FIFO, &scheduling_parameters);

	int c;
	CLProtocol* clInstance;
	int runMode = -1;
	U8 nodeId = 0;

	while ((c = getopt(argc, argv, "n:du")) != -1) {
		switch (c)
		{
			case 'd':
				runMode = CL_DART;
				break;
			case 'u':
				runMode = CL_URT;
				break;
			case 'n':
				nodeId = atoi(optarg);
				break;

			case '?':
		           if (optopt == 'n')
		               fprintf (stderr, "Option -%c requires an argument.\n", optopt);
		             else if (isprint (optopt))
		               fprintf (stderr, "Unknown option `-%c'.\n", optopt);
		             else
		               fprintf (stderr,
		                        "Unknown option character `\\x%x'.\n",
		                        optopt);
		             return 1;
		   default:
		        abort();

		}
	}

	if(nodeId == 0) {
		nodeId = 1;
	}

	switch(runMode)
	{
		case CL_DART:
			clInstance = new DART(nodeId);
			break;
		case CL_URT:
			clInstance = new URT(nodeId);
			break;
		default:
			NOTIFY("Select an Underlying Protocol DART (d) or URT (u)\n");
			exit(EXIT_FAILURE);
			break;
	}

	pthread_t thread1;
	pthread_create(&thread1, NULL, &debugLatency, clInstance);
	clInstance->run();


	delete clInstance;
	munlockall(); /*unlock process memory pages in RAM*/
	exit(EXIT_SUCCESS);
}
